import dayjs from 'dayjs';
import lodash from 'lodash';
import { getMoney } from './money';

export type FormatNumberConfig = {
  precision: number;
  addonBefore: string | undefined;
  addonAfter: string | undefined;
};

export function toPathname(uri: URL) {
  return `${uri.pathname}${uri.search}${uri.hash}`;
}

export const utils = {
  arrayToTree: <T>(
    array: T[],
    childKey = 'id',
    parentKey = 'pid',
    options?: { childrenKey: string; idKey: string },
  ) => {
    const { childrenKey = 'children', idKey = 'key' } = options || {};
    const result: T[] = [];
    const hash: any = {};
    const data = lodash.cloneDeep(array || []);

    data.forEach((item: T) => {
      // @ts-ignore
      // hash[data[index][idKey]] = data[index];
      hash[item[childKey]] = item;
    });

    data.forEach((item: any) => {
      // @ts-ignore
      const hashParent = hash[item[parentKey]];
      if (hashParent) {
        if (hashParent[idKey]) {
          if (!item[`treeKeyPath`]) {
            item[`treeKeyPath`] = [];
          }
          item[`treeKeyPath`] = [
            ...(hashParent[`treeKeyPath`] || []),
            hashParent[idKey],
          ];
        }

        if (!hashParent[childrenKey]) {
          hashParent[childrenKey] = [];
        }
        hashParent[childrenKey].push(item);
      } else {
        result.push(item);
      }
    });

    return result;
  },
  findTree: <T>(
    array: T[],
    id: any,
    idKey = 'id',
    childrenKey = 'children',
  ) => {
    if (!array) {
      return undefined;
    }
    const item = lodash.find(array, (o: any) => o[idKey] === id) as T;
    if (item) {
      return item;
    }

    for (const item of array) {
      const childItem = utils.findTree<T>(
        // @ts-ignore
        item[childrenKey] as T[],
        id,
        idKey,
        childrenKey,
      ) as T;
      if (childItem) {
        return childItem;
      }
    }

    return undefined;
  },
  delay: (delayTime = 500) => {
    return new Promise((resolve) => {
      // @ts-ignore
      setTimeout(() => resolve(), delayTime);
    });
  },
  waitTime: (time: number = 100) => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(true);
      }, time);
    });
  },
  loadScript: (url: string) => {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;
    document.body.appendChild(script);
  },
  bytesToSize: (bytes: number) => {
    if (bytes === 0) return '0 B';
    let k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    let num = Math.round((bytes / Math.pow(k, i)) * 100) / 100;
    return `${num} ${sizes[i]}`;
  },
  formatMoney: getMoney,
  formatNumber: (
    text: number | string | undefined,
    config?: FormatNumberConfig,
  ) => {
    return `${config?.addonBefore || ''}${new Intl.NumberFormat(undefined, {
      ...{
        minimumFractionDigits: config?.precision,
        maximumFractionDigits: config?.precision,
      },
    }).format(Number(text) as number)}${config?.addonAfter || ''}`;
  },
  formatJsonString: (text: string | object) => {
    try {
      if (lodash.isString(text)) {
        return JSON.stringify(JSON.parse(text as any), null, 2);
      }
      return JSON.stringify(text, null, 2);
    } catch (e) {
      return text;
    }
  },
  /**
   * 格式化秒
   *
   * @returns {string}
   * @param second
   */
  secondsToDHMS: (second: number) => {
    let seconds = second;
    let formatText = '';
    const days = Math.floor(seconds / (3600 * 24));
    seconds %= 3600 * 24;

    const hours = Math.floor(seconds / 3600);
    seconds %= 3600;

    const minutes = Math.floor(seconds / 60);
    seconds %= 60;

    if (seconds > 0) {
      formatText = `${seconds}秒`;
    }
    if (minutes > 0) {
      formatText = `${minutes}分钟${formatText}`;
    }
    if (hours > 0) {
      formatText = `${hours}小时${formatText}`;
    }
    if (days > 0) {
      formatText = `${days}天${formatText}`;
    }
    return formatText;
  },
  codeGenerate: (prefix?: string, suffix?: string) => {
    const pair1 = dayjs().format('YYMMDDHHmmss');
    const randomValue = lodash.random(1000, 9999);
    return `${prefix || ''}${pair1}${randomValue}${suffix || ''}`;
  },
  generateRandomString: (length: number) => {
    // 数字和小写的字母,剔除一些难以辨别的数字和字母
    const chars = '23456789abcdefghijkmnpqrstuvwxyz';
    return lodash.times(length, () => lodash.sample(chars)).join('');
  },

  /**
   * 将 searchObj 对象添加到 url 中
   * 例如：{foo=bar},www.bar.com?foo=bar
   * @param url
   * @param searchObj
   * @param toPath
   */
  addSearch: (
    url: string,
    searchObj: Record<string, any>,
    toPath?: boolean,
  ) => {
    const uri = new URL(url);
    lodash.forIn(searchObj, (v, key) => {
      if (uri.searchParams.has(key)) {
        uri.searchParams.delete(key);
      }
      uri.searchParams.append(key, v);
    });
    return toPath === true ? toPathname(uri) : uri.toString();
  },
  removeSearch: (url: string, key: string) => {
    const uri = new URL(url);
    uri.searchParams.delete(key);
    return toPathname(uri);
  },
};
